package repository

import (
	"context"
	"time"

	"github.com/devops-smartbot/devops-smartbot/services/api-gateway/internal/models"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// KnowledgeRepository defines interface for knowledge data access
type KnowledgeRepository interface {
	Create(ctx context.Context, doc *models.KnowledgeDoc) error
	GetByID(ctx context.Context, id string) (*models.KnowledgeDoc, error)
	List(ctx context.Context, params models.KnowledgeQueryParams) ([]*models.KnowledgeDoc, int64, error)
	Update(ctx context.Context, id string, doc *models.KnowledgeDoc) error
	Delete(ctx context.Context, id string) error
	IncrementView(ctx context.Context, id string) error
	GetCategories(ctx context.Context) ([]string, error)
	GetPopular(ctx context.Context, limit int) ([]*models.KnowledgeDoc, error)
}

// MongoKnowledgeRepository implements KnowledgeRepository using MongoDB
type MongoKnowledgeRepository struct {
	collection *mongo.Collection
}

// NewMongoKnowledgeRepository creates a new MongoDB knowledge repository
func NewMongoKnowledgeRepository(db *mongo.Database) KnowledgeRepository {
	return &MongoKnowledgeRepository{
		collection: db.Collection("knowledge"),
	}
}

func (r *MongoKnowledgeRepository) Create(ctx context.Context, doc *models.KnowledgeDoc) error {
	doc.CreatedAt = time.Now()
	doc.UpdatedAt = time.Now()
	doc.ViewCount = 0
	doc.LikeCount = 0

	_, err := r.collection.InsertOne(ctx, doc)
	return err
}

func (r *MongoKnowledgeRepository) GetByID(ctx context.Context, id string) (*models.KnowledgeDoc, error) {
	var doc models.KnowledgeDoc
	err := r.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
	if err == mongo.ErrNoDocuments {
		return nil, nil
	}
	return &doc, err
}

func (r *MongoKnowledgeRepository) List(ctx context.Context, params models.KnowledgeQueryParams) ([]*models.KnowledgeDoc, int64, error) {
	filter := bson.M{}

	if params.Search != "" {
		filter["$or"] = []bson.M{
			{"title": bson.M{"$regex": params.Search, "$options": "i"}},
			{"content": bson.M{"$regex": params.Search, "$options": "i"}},
		}
	}

	if params.Category != "" {
		filter["category"] = params.Category
	}

	if len(params.Tags) > 0 {
		filter["tags"] = bson.M{"$in": params.Tags}
	}

	if params.Status != "" {
		filter["status"] = params.Status
	}

	// Count total
	total, err := r.collection.CountDocuments(ctx, filter)
	if err != nil {
		return nil, 0, err
	}

	// Pagination
	page := params.Page
	if page <= 0 {
		page = 1
	}
	pageSize := params.PageSize
	if pageSize <= 0 {
		pageSize = 20
	}

	opts := options.Find().
		SetSkip(int64((page - 1) * pageSize)).
		SetLimit(int64(pageSize)).
		SetSort(bson.D{{Key: "createdAt", Value: -1}})

	cursor, err := r.collection.Find(ctx, filter, opts)
	if err != nil {
		return nil, 0, err
	}
	defer cursor.Close(ctx)

	var docs []*models.KnowledgeDoc
	if err := cursor.All(ctx, &docs); err != nil {
		return nil, 0, err
	}

	return docs, total, nil
}

func (r *MongoKnowledgeRepository) Update(ctx context.Context, id string, doc *models.KnowledgeDoc) error {
	doc.UpdatedAt = time.Now()
	update := bson.M{"$set": doc}
	_, err := r.collection.UpdateOne(ctx, bson.M{"_id": id}, update)
	return err
}

func (r *MongoKnowledgeRepository) Delete(ctx context.Context, id string) error {
	_, err := r.collection.DeleteOne(ctx, bson.M{"_id": id})
	return err
}

func (r *MongoKnowledgeRepository) IncrementView(ctx context.Context, id string) error {
	update := bson.M{"$inc": bson.M{"viewCount": 1}}
	_, err := r.collection.UpdateOne(ctx, bson.M{"_id": id}, update)
	return err
}

func (r *MongoKnowledgeRepository) GetCategories(ctx context.Context) ([]string, error) {
	categories, err := r.collection.Distinct(ctx, "category", bson.M{"status": "published"})
	if err != nil {
		return nil, err
	}

	result := make([]string, len(categories))
	for i, cat := range categories {
		result[i] = cat.(string)
	}
	return result, nil
}

func (r *MongoKnowledgeRepository) GetPopular(ctx context.Context, limit int) ([]*models.KnowledgeDoc, error) {
	opts := options.Find().
		SetSort(bson.D{{Key: "viewCount", Value: -1}}).
		SetLimit(int64(limit))

	cursor, err := r.collection.Find(ctx, bson.M{"status": "published"}, opts)
	if err != nil {
		return nil, err
	}
	defer cursor.Close(ctx)

	var docs []*models.KnowledgeDoc
	if err := cursor.All(ctx, &docs); err != nil {
		return nil, err
	}

	return docs, nil
}
